(function (window) {

	var WORKER_PATH = 'js/recorderWorker.js';
	var encoderWorker = new Worker('js/mp3Worker.js');

	var Recorder = function (source, cfg) {
		var config = cfg || {};
		var bufferLen = config.bufferLen || 4096;
		var numChannels = config.numChannels || 2;
		this.context = source.context;
		this.node = (this.context.createScriptProcessor ||
			this.context.createJavaScriptNode).call(this.context,
			bufferLen, numChannels, numChannels);
		var worker = new Worker(config.workerPath || WORKER_PATH);
		worker.postMessage({
			command: 'init',
			config: {
				sampleRate: this.context.sampleRate,
				numChannels: numChannels
			}
		});
		var recording = false,
			currCallback;

		this.node.onaudioprocess = function (e) {
			if (!recording) return;
			var buffer = [];
			for (var channel = 0; channel < numChannels; channel++) {
				buffer.push(e.inputBuffer.getChannelData(channel));
			}
			worker.postMessage({
				command: 'record',
				buffer: buffer
			});
		}

		this.configure = function (cfg) {
			for (var prop in cfg) {
				if (cfg.hasOwnProperty(prop)) {
					config[prop] = cfg[prop];
				}
			}
		}

		this.record = function () {
			recording = true;
		}

		this.stop = function () {
			recording = false;
		}

		this.clear = function () {
			worker.postMessage({ command: 'clear' });
		}

		this.getBuffer = function (cb) {
			currCallback = cb || config.callback;
			worker.postMessage({ command: 'getBuffer' })
		}

		this.exportWAV = function (cb, type) {
			currCallback = cb || config.callback;
			type = type || config.type || 'audio/wav';
			if (!currCallback) throw new Error('Callback not set');
			worker.postMessage({
				command: 'exportWAV',
				type: type
			});
		}

		//Mp3 conversion
		worker.onmessage = function (e) {
			var blob = e.data;
			//console.log("the blob " +  blob + " " + blob.size + " " + blob.type);

			var arrayBuffer;
			var fileReader = new FileReader();

			fileReader.onload = function () {
				arrayBuffer = this.result;
				var buffer = new Uint8Array(arrayBuffer),
					data = parseWav(buffer);


				console.log("Converting to Mp3");
				log.innerHTML += "\n" + "Converting to Mp3";

				encoderWorker.postMessage({
					cmd: 'init', config: {
						mode: 3,
						channels: 1,
						samplerate: data.sampleRate,
						bitrate: data.bitsPerSample
					}
				});

				encoderWorker.postMessage({ cmd: 'encode', buf: Uint8ArrayToFloat32Array(data.samples) });
				encoderWorker.postMessage({ cmd: 'finish' });
				encoderWorker.onmessage = function (e) {
					if (e.data.cmd == 'data') {

						console.log("Done converting to Mp3");
						log.innerHTML += "\n" + "Done converting to Mp3";

						/*var audio = new Audio();
						audio.src = 'data:audio/mp3;base64,'+encode64(e.data.buf);
						audio.play();*/

						//console.log ("The Mp3 data " + e.data.buf);

						var mp3Blob = new Blob([new Uint8Array(e.data.buf)], { type: 'audio/mp3' });
						console.log('upload mp3');

						uploadAudio(mp3Blob);

						var url = 'data:audio/mp3;base64,' + encode64(e.data.buf);
						var li = document.createElement('li');
						var au = document.createElement('audio');
						var hf = document.createElement('a');

						au.controls = true;
						au.src = url;
						hf.href = url;
						hf.download = 'audio_recording_' + new Date().getTime() + '.mp3';
						hf.innerHTML = hf.download;
						li.appendChild(au);
						li.appendChild(hf);
						recordingslist.appendChild(li);

					}
				};
			};

			fileReader.readAsArrayBuffer(blob);

			currCallback(blob);
		}


		function encode64(buffer) {
			var binary = '',
				bytes = new Uint8Array(buffer),
				len = bytes.byteLength;

			for (var i = 0; i < len; i++) {
				binary += String.fromCharCode(bytes[i]);
			}
			return window.btoa(binary);
		}

		function parseWav(wav) {
			function readInt(i, bytes) {
				var ret = 0,
					shft = 0;

				while (bytes) {
					ret += wav[i] << shft;
					shft += 8;
					i++;
					bytes--;
				}
				return ret;
			}
			if (readInt(20, 2) != 1) throw 'Invalid compression code, not PCM';
			if (readInt(22, 2) != 1) throw 'Invalid number of channels, not 1';
			return {
				sampleRate: readInt(24, 4),
				bitsPerSample: readInt(34, 2),
				samples: wav.subarray(44)
			};
		}

		function Uint8ArrayToFloat32Array(u8a) {
			var f32Buffer = new Float32Array(u8a.length);
			for (var i = 0; i < u8a.length; i++) {
				var value = u8a[i << 1] + (u8a[(i << 1) + 1] << 8);
				if (value >= 0x8000) value |= ~0x7FFF;
				f32Buffer[i] = value / 0x8000;
			}
			return f32Buffer;
		}

		function uploadAudio(mp3Data) {

			var reader = new FileReader();
			reader.onload = function (event) {
				var fd = new FormData();
				var mp3Name = encodeURIComponent('audio_recording_' + new Date().getTime() + '.mp3');
				console.log("mp3name = " + mp3Name);
				fd.append('fname', mp3Name);
				fd.append('data', event.target.result);

				$.ajax({
					type: 'POST',
					url: 'upload.php',
					data: fd,
					processData: false,
					contentType: false
				}).done(function (data) {
					//console.log(data);
					log.innerHTML += "\n" + data;
				});
			};
			reader.readAsDataURL(mp3Data);
		}

		source.connect(this.node);
		this.node.connect(this.context.destination);    //this should not be necessary
	};

  /*Recorder.forceDownload = function(blob, filename){
	console.log("Force download");
    var url = (window.URL || window.webkitURL).createObjectURL(blob);
    var link = window.document.createElement('a');
    link.href = url;
    link.download = filename || 'output.wav';
    var click = document.createEvent("Event");
    click.initEvent("click", true, true);
    link.dispatchEvent(click);
  }*/

	window.Recorder = Recorder;

})(window);
